CONTENTS |
Since the advent of the Servlets API, Java developers have been able to work behind a web server interface. For reasons of price, convenience, and ready availability, Apache has long been a popular choice for Java developers, holding its own in a programming world otherwise largely dominated by commercial tools.
The Apache-approved method for adding Java support to Apache is to use Tomcat. This is an open source version of the Java servlet engine that installs itself into Apache. The interpreter is always available, without being loaded at each call, to run your scripts. The old way to run Java with Apache was via JServ — which is now (again, in theory) obsolete on its own. JServ and Tomcat are both Java applications that talk to Apache via an Apache module (mod_jserv for JServ and mod_jk for Tomcat), using a socket to get from Apache to the JVM.
In practice, we had considerable difficulty with Tomcat. Since mod_jserv is still maintained and is not (all that) difficult to install, Java enthusiasts might like to try it. We will describe JServ first and then Tomcat. For more on Servlet development in general, see Jason Hunter's Java Servlet Programming (O'Reilly, 2001).
Windows users should get the self-installing .exe distribution from http://java.apache.org/.
Download the gzipped tar file from http://java.apache.org/, and unpack it in a suitable place — we put it in /usr/src/mod_jserv.
The READMEfile says:
Apache JServ is a 100% pure Java servlet engine designed to implement the Sun Java Servlet API 2.0 specifications and add Java Servlet capabilities to the Apache HTTP Server.
For this installation to work, you must have:
But not Apache v2, which does not support mod_jserv.
We decided to install the full Java Development Kit (which we needed anyway for Tomcat — see later on). We went to the FreeBSD site and downloaded the 1.1.8 JDK from ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/local-distfiles/nate/JDK1.1/jdk1.1.8_ELF.V1999-11-9.tar.gz.
If you are adventurous, 1.2 is available from http://www.freebsd.org/java/dists/12.html. When you have it, see Section 18.2.1 for what to do next. If you are using a different operating system from any of those mentioned, you will have to find the necessary package for yourself.
A range of versions is available at http://java.sun.com/products/servlet/download.html. As is usual with anything to do with Java, a certain amount of confusion is evident. The words "Java Servlet Development Kit" or "JSDK" are hard to find on this page, and when found they seem to refer to the very oldest versions rather than the newer ones that are called "Java Servlet." However, we felt that older is probably better in the fast-moving but erratic world of Java, and we downloaded v2.0 from http://java.sun.com/products/servlet/archive.html. This offered both Windows and "Unix (Solaris and others)" code, with the reassuring note: "The Unix download is labeled as being for Solaris but contains no Solaris specific code." The tar file arrived with a .Z extension, signifying that it needs to be expanded with the Unix utility uncompress. There is a FreeBSD JSDK available atftp://ftp.FreeBSD.org/pub/FreeBSD/branches/-current/ports/java/jsdk.tar.
If you downloaded the Runtime Environment listed earlier, rather than the JDK, you will also need a compiler — either Sun's Javac (see web site listed earlier) or the faster Jikes compiler from IBM at http://www.alphaworks.ibm.com/tech/jikes.
If you have already downloaded the Apache source and compiled it successfully, you must have this component. But there is a hidden joke in that mod_jserv will not be happy with any old make utility. It must and will have a GNU make from ftp://ftp.gnu.org/gnu/make/. See the next section.
mod_jserv uses GNU make, which is incompatible with all other known makes. So, you may need to get (from http://www.gnu.org/software/make/make.html) and build GNU make before starting. If you do, here's how we did it.
Since you probably already have a perfectly good make, you don't want the new one to get mixed up with it. Just for safety's sake, you might want to back up your real make before you start.
Create a directory for the sources as usual, unpack them, and make gmake (cunningly not called make) with the commands:
./configure --program-prefix=g make make install
You should end up with /usr/local/bin/gmake.
Having created gmake, move to the mod_jserv source directory. Before you start, you need to have compiled Apache so that JServ can pass its configure checks. If you have got this far in the book, you probably will already have compiled Apache once or twice, but if not — now is a good time to start. Go to Chapter 1.
You then need to decide whether you want to build it into the Apache executable (recommended) or prepare it as a DSO. We took the first route and configured mod_jserv with this:
MAKE=/usr/local/bin/gmake ./configure --prefix=/usr/local --with-apache-src=/usr/src/ apache/apache_1.3.19 --with-jdk-home=/usr/src/java/jdk1.1.8 --with-JSDK=/usr/src/ jsdk/JSDK2.0/lib
Your paths in general will be different. --prefix invokes the location where you want the JServ bits to be put. Rather perversely, they appear in the subdirectory .../etc below the directory you specify. You might also think that you were required to put /src on the end of the Apache path, but you're not. If the process fails for any reason, take care to delete the file config.cache before you try again. You might want to write the necessary commands as a script since it is unlikely to work at the first attempt:
rm config.cache MAKE=/usr/local/bin/gmake ./configure --prefix=/usr/local/bin --with-apache-src=/usr/src/ apache/apache_1.3.19 --with-jdk-home=/usr/src/java/jdk1.1.8 --with-JSDK=/usr/src/ jsdk/JSDK2.0/lib > log
If you use mod_ssl, you should add --enable-EAPI. The script's voluminous comments will appear in the file log; error messages will go the screen. Any mistakes in this script can produce rather puzzling error messages. For instance, on our first attempt we misspelled --with-JSDK as --with-JDSK. The error message was:
checking JSDK ... configure: error: Does not exist: '/usr/local/JSDK2.0
which was true enough. Yet it required a tour through the Configure file to realize that the script had failed to match --with-JDSK, said nothing about it, and had then gone to its default location for JSDK.
When ./configure has done its numerous things, it prints some sage advice on what to do next, which would normally disappear off the top of the screen, but which you will find at the bottom of the log file:
+-STEP 1-------------------------------------------------------+ |Run 'make; make install' to make a .jar file, compile the C | |code and copy the appropriate files to the appropriate | |locations. | +--------------------------------------------------------------+ +-STEP 2-------------------------------------------------------+ |Then cd /usr/src/apache/apache_1.3.19 and run 'make; make install' +--------------------------------------------------------------+ +-STEP 3-------------------------------------------------------+ |Put this line somewhere in Apache's httpd.conf file: | |Include /usr/src/jserv/ApacheJServ-1.1.2/etc/jserv.conf | | |Then start Apache and try visiting the URL: | |http://my586.my.domain:SERVER_PORT/servlets/Hello | | |If that works then you have successfully setup Apache JServ. | | | |If that does not work then you should read the | |troubleshooting notes referenced below. | +--------------------------------------------------------------+ +-Troubleshooting----------------------------------------------+ |Html documentation is available in the docs directory. | | | |Common Errors: | | Make sure that the log files can be written to by the | | user your httpd is running as (ie: nobody). If there are | | errors in your configuration, they will be logged there. | | | |Frequently asked questions are answered in the FAQ-O-Matic: | | | | http://java.apache.org/faq/ | +--------------------------------------------------------------+
You should carry on with:
gmake
Then:
gmake install
Now go to /usr/src/apache/apache_1.3.19 (or whatever your path is to the Apache sources). Do not go down to the src subdirectory as we did originally. Then:
./configure --activate-module=src/modules/jserv/libjserv.a make make install
We saw some complaints from make. This time the comments are output to stderr. You can capture them with:
make install &> log2.
The comments end with:
+--------------------------------------------------------+ | You now have successfully built and installed the | | Apache 1.3 HTTP server. To verify that Apache actually | | works correctly you now should first check the | | (initially created or preserved) configuration files | | | | /usr/local/etc/httpd/httpd.conf | | | and then you should be able to immediately fire up | | Apache the first time by running: | | | | /usr/local/sbin/apachectl start | | | Thanks for using Apache. The Apache Group | | http://www.apache.org/ | +--------------------------------------------------------+
This is not very helpful because:
The Config file is a variant of the enormous Apache "include everything" file which we think is confusing and retrograde.
The Config file actually said nothing about JServ.
The command /usr/local/sbin/apachectl start didn't work because Apache looked for the Config file in the wrong place.
But, in our view, building the executable is hard enough; one shouldn't expect the installation to work as well. The new httpd file is in .../src. Go there and check that everything worked by typing:
./httpd -l
A reference to mod_jserv.c among the "compiled-in modules" would be pleasing. Remember: if you forget ./, you'll likely run the httpd in /usr/local/bin, which probably won't know anything about JServ.) We then copied httpd to /usr/local/sbin/httpd_jserv.
If it is there, you can proceed to test that it all works by setting up site.jserv (a straight copy of site.simple) with this line in the Config file — making sure that the path suits:
Include /usr/local/bin/etc/jserv.conf
Finally, start Apache (as /usr/local/sbin/httpd_jserv), and visit http://www.butterthlies.com/servlets/Hello. You should see something like this:
Example Apache JServ Servlet Congratulations, ApacheJServ 1.1.2 is working!
Sadly, the Earth didn't quite move for both of us. Ben's first attempt failed. The problem was that his supplied jserv.conf was not quite set up correctly. The solution was to copy it into our own configuration file and edit it appropriately. The problem we saw was this:
Syntax error on line 43 of /usr/local/jserv/etc/jserv.conf: ApJServLogFile: file '/home/ben/www3/NONE/logs/mod_jserv.log' can't be opened
We corrected this to be a sensible path, and then Apache started. But attempting to access the sample servlet caused an internal error in Apache. The error log said:
java.io.IOException: Directory not writable: //NONE/logs at org.apache.java.io.LogWriter.<init>(LogWriter.java:287) at org.apache.java.io.LogWriter.<init>(LogWriter.java:203) at org.apache.jserv.JServLog.<init>(JServLog.java:92) at org.apache.jserv.JServ.start(JServ.java:233) at org.apache.jserv.JServ.main(JServ.java:158)
We had to read the source to figure this one out, but it turned out that /usr/local/jserv/etc/jserv.properties had the line:
log.file=NONE/logs/jserv.log
presumably for the same reason that jserv.conf was wrong. To fix this we took our own copy of the properties file (which is used by the Java part of JServ) and changed the path. To use the new properties file, we had to change its location in our httpd.conf:
ApJServProperties /usr/local/jserv/etc/jserv.properties
This still didn't cure our problems. This time the error appeared in the jserv.log file we've just reconfigured earlier:
[28/04/2001 11:17:48:420 GMT] Error creating classloader for servlet zone root : java.lang.IllegalArgumentException: Repository //NONE/servlets doesn't exist!
This error relates to a servlet zone, called root — this is defined in jserv.properties by two directives:
zones=root root.properties=/usr/local/jserv/etc/zone.properties
So now the offending file is zone.properties, which we copied, changed its location in jserv.properties, and corrected:
repositories=NONE/servlets
We changed this to point at the example directory in the source of JServ, which has a precompiled example servlet in it, in our case:
repositories=/home/ben/software/unpacked/ApacheJServ-1.1.2/example
and finally, surfing to the Hello server (http://your.server/servlets/Hello) gave us a well-deserved "congratulations" page.
JServ has its own Apache directives, which are documented in the jserv.conf file.
To run JServ on Win32, tell Apache to load the Apache JServ communication module with:
... LoadModule jserv_module modules/ApacheModuleJServ.dll ...
If JServ is to be run as a Shared Object, tell Apache on Unix to load the Apache JServ communication module:
LoadModule jserv_module /usr/local/bin/libexec/mod_jserv.so
It would be sensible to wrap the JServ directives in this:
<IfModule mod_jserv.c>
ApJservManual |
ApJServManual [on/off] Default: "Off" |
Whether Apache should start JServ or not (On=Manual Off=Autostart). Somewhat confusingly, you probably want Off, meaning "start JServ." But since this is the default, you can afford to ignore the whole question.
ApJServProperties |
ApJServProperties [filename] Default: "./conf/jserv.properties" |
Properties filename for Apache JServ in automatic mode. In manual mode this directive is ignored.
ApJServProperties /usr/local/bin/etc/jserv.properties
ApJServLogFile |
ApJServLogFile [filename] Default: "./logs/mod_jserv.log" |
Log file for this module operation relative to Apache root directory. Set the name of the trace/log file. To avoid possible confusion about the location of this file, an absolute pathname is recommended. This log file is different from the log file that is in the jserv.properties file. This is the log file for the C portion of Apache JServ.
On Unix, this file must have write permissions by the owner of the JVM process. In other words, if you are running Apache JServ in manual mode and Apache is running as user nobody, then the file must have its permissions set so that that user can write to it.
|
ApJServLogFile /usr/local/var/httpd/log/mod_jserv.log
ApJServLogFile |
ApJServLogLevel [debug|info|notice|warn|error|crit|alert|emerg] Default: info (unless compiled w/ JSERV_DEBUG, in which case it's debug) |
Log Level for this module.
ApJServLogLevel notice
ApJServDefaultProtocol |
ApJServDefaultProtocol [name] Default: "ajpv12" |
Protocol used by this host to connect to Apache JServ. As far as we know, the default is the only possible protocol, so the directive can be ignored. There is a newer version but it only works with mod_jk — see later.
ApJServDefaultProtocol ajpv12
ApJServDefaultHost |
ApJServDefaultHost [hostname] Default: "localhost" |
Default host on which Apache JServ is running.
ApJServDefaultHost java.apache.org
ApJServDefaultPort |
ApJServDefaultPort [number] Default: protocol-dependant (for ajpv12 protocol this is "8007") |
Default port to which Apache JServ is listening.
ApJServDefaultPort 8007
ApJServVMTimeout |
ApJServVMTimeout [seconds] Default: 10 seconds |
The amount of time to give to the JVM to start up, as well as the amount of time to wait to ping the JVM to see if it is alive. Slow or heavily loaded machines might want to increase this value.
ApJServVMTimeout 10
ApJServProtocolParameter |
ApJServProtocolParameter [name] [parameter] [value] Default: NONE |
Passes parameter and value to specified protocol.
|
ApJServSecretKey |
ApJServSecretKey [filename] Default: "./conf/jserv.secret.key" |
Apache JServ secret key file relative to Apache root directory.
|
ApJServSecretKey /usr/local/bin/etc/jserv.secret.key ApJServSecretKey DISABLED
ApJServMount |
ApJServMount [name] [jserv-url] Default: NONE |
Mount point for Servlet zones (see documentation for more information on servlet zones)
|
ApJServMountCopy |
ApJServMountCopy [on/off] Default: "On" |
Whether <VirtualHost> inherits base host mount points or not.
|
ApJServMountCopy on
ApJServAction |
ApJServAction [extension] [servlet-uri] Defaults: NONE |
Executes a servlet passing filename with proper extension in PATH_TRANSLATED property of servlet request.
|
ApJServAction .jsp /servlets/org.gjt.jsp.JSPServlet ApJServAction .gsp /servlets/com.bitmechanic.gsp.GspServlet ApJServAction .jhtml /servlets/org.apache. servlet.ssi.SSI ApJServAction .xml /servlets/org.apache.cocoon.Cocoon
Enable the Apache JServ status handler with the URL of http://servername/jserv/ (note the trailing slash!). Change the deny directive to restrict access to this status page:
<Location /jserv/> SetHandler jserv-status order deny,allow deny from all allow from 127.0.0.1 </Location>
|
Now that we have JServ running, let's add a little servlet to it, just to show how its done. Of course, there's already a simple servlet in the JServ package, the Hello servlet mentioned earlier; the source is in the example directory, so take a look. We wanted to do something just a little more interesting, so here's another servlet called Simple, which shows the parameters passed to it. As always, Java requires plenty of code to make this happen, but there you are:
import java.io.PrintWriter; import java.io.IOException; import java.util.Enumeration; import java.util.Hashtable; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpUtils; public class Simple extends HttpServlet { public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { PrintWriter out; String qstring=request.getQueryString( ); Hashtable query; if(qstring == null) qstring=""; try { query=HttpUtils.parseQueryString(qstring); } catch(IllegalArgumentException e) { query=new Hashtable( ); String tmp[]=new String[1]; tmp[0]=qstring; query.put("bad query",tmp); } response.setContentType("text/html"); out=response.getWriter( ); out.println("<HTML><HEAD><TITLE>Simple Servlet</TITLE></HEAD>"); out.println("<BODY>"); out.println("<H1>Simple Servlet</H1>"); for(Enumeration e=query.keys( ) ; e.hasMoreElements( ) ; ) { String key=(String)e.nextElement( ); String values[]=(String [])query.get(key); for(int n=0 ; n < values.length ; ++n) out.println("<B>"+key+"["+n+"]"+"=</B>"+values[n]+"<BR>"); } out.println("</BODY></HTML>"); out.close( ); } }
We built this like so:
javac -classpath /home/ben/software/jars/jsdk-2.0.jar:/usr/local/jdk1.1.8/lib/ classes.zip Simple.java
That is, we supplied the path to the JSDK and the base JDK classes. All that is needed then is to enable it — the simplest way to do that is to add the directory Simple.java into the repository list for the root zone, by setting the following in zone.properties:
repositories=/home/ben/software/unpacked/ApacheJServ-1.1.2/example,/home/ben/work/ suppose-apachebook/samples/servlet-simple
That is, we added the directory to the existing one with a comma. We then test it by surfing to http://your.server/servlets/Simple.If we want, we can add some parameters, and they'll be displayed. For example,http://your.server/servlets/Simple?name=Ben&name=Peter&something=else should result in the following:
Simple Servlet something[0]=else name[0]=Ben name[1]=Peter
If anything goes wrong with your servlet, you should find the error and stack backtrace in jserv.log.
Of course, you could create a completely new zone for the new servlet, but that struck us as overkill.
Tomcat, part of the Jakarta Project, is the modern version of JServ and is able to act as a server in its own right. But we feel that it will be a long time catching up with Apache and that it would not be a sensible choice as the standalone server for a serious web site.
The home URL for the Jakarta project is http://jakarta.apache.org/, where we are told:
The goal of the Jakarta Project is to provide commercial-quality server solutions based on the Java Platform that are developed in an open and cooperative fashion.
At the time of writing, Tomcat 4.0 was incompatible with Apache's mod-cgi, and in any case requires Java 1.2, which is less widely available than Java 1.1, so we decided to concentrate on Tomcat 3.2.
In the authors' experience, installing anything to do with Java is a very tiresome process, and this was no exception. The assumption seems to be that Java is so fascinating that proper explanations are unnecessary — devotees will immerse themselves in the holy stream and all will become clear after many days beneath the surface. This is probably because explanations are expensive and large commercial interests are involved. It contrasts strongly with the Apache site or the Perl CPAN network, both of which are maintained by unpaid enthusiasts and usually, in our experience, are easy to understand and work immaculately.
First, you need a Java Development Kit (JDK). We downloaded jdk1.1.8 for FreeBSD[1] from http://java.sun.com and installed it. Another source is ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/local-distfiles/nate/JDK1.1/jdk1.1.8_ELF.V1999-11-9.tar.gz. Installation is simple: you just unzip the tarball and then extract the files. If you read the README without paying close attention, you may get the impression that you need to unzip the src.zip file — you do not, unless you want to read the source code of the Java components. And, of course, you absolutely must not unzip classes.zip.
An essential step that may not be very clear from the documentation is to include the JDK, at ..../usr/src/java/jdk1.1.8/bin on your path, to set the environment variable CLASSPATH to /usr/src/java/jdk1.1.8/lib/classes.zip and to add the current directory to the path if it isn't already there.
Make sure that the directory names correspond with the situation on your machine and log in again to get it to work. A simple test to see whether you've got it all together is to write yourself a "hullo world" program:
public class hw { public static void main(String[] args) { System.out.println("Hello World"); } }
Save it with the same name as the public class and the .java extension: hw.java. Compile it with:
javac hw.java
and run it with:
java hw
If Hello World appears on the screen, all is well.
Tomcat can work in three different ways:
As a standalone servlet container. This is useful for debugging and testing, since it also acts a (rather crude) web server. We would not suggest you use it instead of Apache.
As an in-process servlet container running inside Apache's address space. This gives good performance but is poor on scalability when your site's traffic grows.
As an out-of-process servlet container, running in its own address space and communicating with Apache through TCP/IP sockets.
If you decide on 2 or 3, as you probably will, you have to choose which method to use and implement it accordingly.
Consequently, the installation of Tomcat involves two distinct processes: installing Tomcat and adapting Apache to link to it.
Normally we advocate building from source, but in the case of Java it can get tedious, so we decided to install Tomcat from the binary distribution, jakarta.-tomcat-3.3a.tar.gz in our case.
Installation of Tomcat is pretty simple. Having unpacked it, all you have to do is to set the environment variables:
JAVA_HOME to: /usr/src/java/jdk1.1.8 TOMCAT_HOME to /usr/src/tomcat/jakarta-tomcat-3.3a
(or the paths on your machine if they are different) and re-log in. Test that everything works by using the command:
ls $TOMCAT_HOME
If it doesn't produce the contents of this directory, something is amiss.
Installation on Win32 systems is very similar. Set the path to the Tomcat directory by typing:
set TOMCAT_HOME =\usr\src\tomcat\jakarta-tomcat-3.3a"
The .../jakarta-tomcat-3.3a/bin directory contains two scripts: startup.sh, which sets Tomcat running, and shutdown.sh, which stops it. To test that everything is installed properly, go there and run the first. A good deal of screen chat ensues (after rather long pause). Note that the script detaches from the shell early on, so its hard to tell when its finished.
By default, Tomcat logs to the screen, which is not a good idea, so it is wise to modify conf/server.xml from:
... <LogSetter name ="tc_log" verbosityLevel="INFORMATION" /> ...
to:
... <LogSetter name ="tc_log" path="logs/tomcat.log" verbosityLevel="INFORMATION" /> ...
The result is to transfer the screen messages to the log file.
If you now surf to port 8080 on your machine — we went to http://www.butterthlies.com:8080 — Tomcat will show you its home page, which lives at $TOMCAT_HOME/webapps/ROOT/index.html. Note that the page itself erroneously claims to be at $TOMCAT_HOME/webapps/index.html.
When you have had enough of this excitement, you can stop Tomcat with $TOMCAT_HOME/bin/shutdown.sh. If you try to start Tomcat without shutting it down first, you will get a fatal Java error.
In the .../jakarta-tomcat -- 3.3a directory you will find:
Startup, shutdown scripts, tomcat.sh, and others
Configuration files
Various documents, including uguide — the file to print out and keep by you — and FAQ
Jar files
Log files
Sample web applications
Tomcat's own private stuff
We will look through the contents of these subdirectories that need comment.
The startup and shutdown scripts merely call the important one: tomcat.sh. This script does two things:
Guesses a CLASSPATH
Passes command-line arguments to org.apache.tomcat.startup.Tomcat. These include start and stop, plus the location of the appropriate server.xml file (see later), which configures Tomcat. For instance, if you want to use /etc/server_1.xml with Tomcat and Apache, you would start Tomcat with:
bin/tomcat.sh start -f/etc/server_1.xml
This subdirectory contains two important and useful files:
The first is server.xml. This file covers several issues, in most of which you will not have to interfere. For syntax, see the documentation on the default server we ran earlier (in http:/.../doc/serverxml.html).
Each file of the form apps-<somename>.xml is also parsed — this is enabled by the directive:
<ContextXmlReader config="conf/apps.xml" />
which causes both conf/apps.xml and conf/apps-*.xml to be read and contexts to be loaded from them (see the example servlet later for how contexts are used).
We use the Simple.java test servlet described earlier to demonstrate how to install a servlet. First of all we create a directory, .../site.tomcat, and in it a subdirectory called servlets — this is where we will end up pointing Tomcat. In .../site.tomcat/servlets, we create a directory WEB-INF (this is where Tomcat expects to find stuff). In WEB-INF we create another subdirectory called classes. Then we copy Simple.class to .../site.tomcat/servlets/WEB-INF/classes. We then associate the Simple class with a servlet unimaginatively called "test", by creating .../site.tomcat/servlets/WEB-INF/web.xml, containing:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app> <servlet> <servlet-name> test </servlet-name> <servlet-class> Simple </servlet-class> </servlet> </web-app>
Finally, we make Tomcat aware of all this by associating the .../site.tomcat/servlets directory with a context by creating conf/apps-simple.xml (remember, this file will automatically be read by the default configuration) containing:
<?xml version="1.0" encoding="ISO-8859-1"?> <webapps> <Context path="/simple" docBase=".../site.tomcat/servlets" debug="0" reloadable="true" > <LogSetter name="simple_tc.log" path="logs/simple.log" /> <LogSetter name="simple_servlet_log" path="logs/simple_servlet.log" servletLogger="true"/> </Context> </webapps>
Obviously, docBase must be set to the actual path of our directory. The path parameter specifies the first part of the URL that will access this context. The context can contain plain HTML, as well as servlets and JSPs. Servlets appear in the servlet subdirectory of the path, so to access the Simple servlet with the previous configuration, we would use the URL http://.../simple/servlet/test. Surfing to http://.../simple/servlet/test?a=b&c=d&c=e produces the following output:
Simple Servlet c[0]=d c[1]=e a[0]=b
The basic document here is .../doc/tomcat-apache-howto.html. It starts with the discouraging observation:
Since the Tomcat source tree is constantly changing, the information herein may be out of date. The only definitive reference at this point is the source code.
As we have noted earlier, this may make you think that Tomcat is more suited to people who prefer the journey to the destination. You will also want to look at http://jakarta.apache.org/tomcat/tomcat-3.2-doc/uguide/tomcat_ug.html, though the two documents seem to disagree on various points.
The Tomcat interface in Apache is mod_jk. The first job is to get, compile, and install it into Apache. When we downloaded Tomcat earlier, we were getting Java, which is platform independent, and therefore the binaries would do. mod_jk is needed in source form and is distributed with the source version of Tomcat, so we went back to http://jakarta.apache.org/builds/jakarta-tomcat/release/v3.3a/src/ and downloaded jakarta-tomcat-3.3a-src.tar.gz. Things are looking up: when we first tried this, some months before, the tar files for the Tomcat binaries and sources had the same name. When you unpacked one, it obliterated the other.
Before starting, it is important that Apache has been compiled correctly, or this won't work at all. First, it must have been built using configure in the top directory, rather than src/Configure. Second, it must have shared object support enabled; that is, it should have been configured with at least one shared module enabled. An easy way to do this is to use:
./configure --enable-shared=example
Note that if you have previously configured Apache and are running a version prior to 1.3.24, you'll need to remove src/support/apxs to force a rebuild, or things will mysteriously fail. Once built, Apache should then be installed with this:
make install
Once this has been done, we can proceed.
Having unpacked the sources, we went down to the .../src directory. The documentation is in ..../jakarta-tomcat-3.3a-src/src/doc/mod_jk-howto.html.. Set the environment variable $APACHE_HOME (not $APACHE1_HOME despite the documentation) to /usr/local/apache. You also need to set JAVA_HOME as described earlier.
Descend into .../jakarta-tomcat-3.3a-src/src/native/mod_jk/apache-1.3, and execute:
./build-unix.sh
Unfortunately, this suffers from the "everything is Linux" syndrome and used weird options to the find utility. We fixed it by changing the line:
JAVA_INCLUDE="`find ${JAVA_HOME}/include -type d -printf \"-I %p \"`" || echo "find failed, edit build-unix.sh source to fix"
to:
JAVA_INCLUDE="`find ${JAVA_HOME}/include -type d | sed 's/^/-I /g'`" || echo "find failed, edit build-unix.sh source to fix"
which is substantially more portable. We also had to add this to .../jakarta-tomcat-3.3a-src/src/native/mod_jk/jk_jni_worker.c:
#ifndef RTLD_GLOBAL # define RTLD_GLOBAL 0 #endif
With these two changes, build-unix.sh worked, and we ended up with a mod_jk.so as desired.
If you are running as an appropriately permitted user, build-unix.sh will install mod_jk.so in the libexec directory of the Apache installation (/usr/local/apache/libexec by default).
The next step is to configure Apache to use mod_jk. In fact, Tomcat comes with a sample set of config files for that in .../jakarta-tomcat-3.3a/conf/jk. There are two files that need tweaking to make it work. First, mod_jk.conf:
LoadModule jk_module /usr/local/apache/libexec/mod_jk.so <IfModule mod_jk.c> JkWorkersFile .../jakarta-tomcat-3.3a/conf/jk/workers.properties JkLogFile logs/jk.log JkLogLevel error JkMount /*.jsp ajp12 JkMount /servlet/* ajp12 JkMount /examples/* ajp12 </IfModule>
This is pretty straightforward — we just load mod_jk in the usual way. The JkWorkersFile directive specifies the location of a file with settings for the Java components of mod_jk. JkLogFile and JkLogLevel are self-explanatory. Finally, JkMount sets the mapping from URLs to Tomcat — ajp12 refers to the protocol used to communicate with Apache. In fact, ajp13 is the more modern protocol and should be used in preference, but despite the claims of the documentation, Tomcat's default setup uses ajp12. Simply change ajp12 to ajp13 to switch protocols.
The other file that needs tweaking is workers.properties (we've removed all the comments for brevity; see the real file for copious extra information):
workers.tomcat_home=.../jakarta-tomcat-3.3a workers.java_home=/usr/local/jdk1.1.8 ps=/ worker.list=ajp12, ajp13 worker.ajp12.port=8007 worker.ajp12.host=localhost worker.ajp12.type=ajp12 worker.ajp12.lbfactor=1 worker.ajp13.port=8009 worker.ajp13.host=localhost worker.ajp13.type=ajp13 worker.ajp13.lbfactor=1 worker.loadbalancer.type=lb worker.loadbalancer.balanced_workers=ajp12, ajp13 worker.inprocess.type=jni worker.inprocess.class_path=$(workers.tomcat_home)$(ps)lib$(ps)tomcat.jar worker.inprocess.cmd_line=start worker.inprocess.jvm_lib=$(workers.java_home)$(ps)bin$(ps)javai.dll worker.inprocess.stdout=$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stdout worker.inprocess.stderr=$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stderr
The parts of this that need adjusting are workers.tomcat_home, workers.java_home, ps, and workers.inprocess.jvm_lib. The first two are self-explanatory; ps is simply the path separator for the operating system you are using (i.e., "\" for Windows and "/" for Unix). The last one, worker.inprocess.jvm_lib, should be adjusted according to OS and JVM, as commented in the sample file (but note that unless you are using the inprocess version of Tomcat, this setting won't be used — and by default, you won't be using it).
Finally, we write the actual configuration file for Apache — in this case, we decided to run it on port 8111, for no particular reason, and .../site.tomcat/conf/httpd.conf looks like this:
Port 8111 DocumentRoot .../site.tomcat/www Include .../jakarta-tomcat-3.3a/conf/jk/mod_jk.conf
where the DocumentRoot points at some directory with HTML in it, and the Include is adjusted to point to the mod_jk.conf we altered earlier. Now all that is required is to start Tomcat and Apache in the usual way. Tomcat is started as described earlier, and Apache starts simply with:
httpd -d .../site.tomcat
You should then find that the example servlets are available. In fact, if you set the DocumentRoot to be .../jakarta-tomcat-3.3a/webapps/ROOT, then you should find that your Apache server looks exactly like your Tomcat server, only on a different port.
All that remains is to show how to add our example servlet to this configuration. Nothing could be easier. In mod_jk.conf or httpd.conf, add the line:
JkMount /simple/* ajp13
If everything is set up as we did for plain Tomcat earlier, then the Simple servlet should now work, exactly as it did for plain Tomcat. All we need is that the URL path in the JkMount matches the Context path in the apps-*.xml file.
[1] This is the version of Unix we use — you would download the version appropriate to your OS.
CONTENTS |